Ext.data.DataProxy = function( conn )
{
	conn = conn || {};

	this.api = conn.api; // 定义restful的4中操作
	this.url = conn.url;
	this.restful = conn.restful; // 是否使用REST风格
	this.listeners = conn.listeners;

	// deprecated
	this.prettyUrls = conn.prettyUrls;

	// 添加事件
	this.addEvents('exception', 'beforeload', 'load', 'loadexception', 'beforewrite', 'write');
	// 调用Observable构造函数
	Ext.data.DataProxy.superclass.constructor.call(this);

	try
	{
		Ext.data.Api.prepare(this); // 对REST进行初始化，只要是修改了当前类的一些属性，所以没有返回值
	}
	catch (e)
	{
		if( e instanceof Ext.data.Api.Error )
		{
			e.toConsole();
		}
	}
	// relay each proxy's events onto Ext.data.DataProxy class for centralized Proxy-listening
	Ext.data.DataProxy.relayEvents(this,
	[
	    'beforewrite', 'write', 'exception'
	]);
};

Ext.extend(Ext.data.DataProxy, Ext.util.Observable,
{
	restful: false,
	setApi: function()
	{
		if( arguments.length == 1 )
		{
			var valid = Ext.data.Api.isValid(arguments[0]);
			if( valid === true )
			{
				this.api = arguments[0];
			}
			else
			{
				throw new Ext.data.Api.Error('invalid', valid);
			}
		}
		else if( arguments.length == 2 )
		{
			if( !Ext.data.Api.isAction(arguments[0]) )
			{
				throw new Ext.data.Api.Error('invalid', arguments[0]);
			}
			this.api[arguments[0]] = arguments[1];
		}
		Ext.data.Api.prepare(this);
	},

	isApiAction: function( action )
	{
		return (this.api[action]) ? true : false;
	},

	// 请求代理数据，参数action用来制定REST的CRUD的某种操作，rs为写数据时的数据列表
	// request('read',null,{start:0,limit:10,id:2343,username:'abc'})
	request: function( action, rs, params, reader, callback, scope, options )
	{
		if( !this.api[action] && !this.load )
		{
			throw new Ext.data.DataProxy.Error('action-undefined', action);
		}
		params = params || {};
		if( (action === Ext.data.Api.actions.read) ? this.fireEvent("beforeload", this, params) : this.fireEvent("beforewrite", this, action, rs, params) !== false )
		{
			// 调用模板函数来实现具体的代理请求功能
			this.doRequest.apply(this, arguments);
		}
		else
		{
			// 失败的话就直接执行回调函数了
			callback.call(scope || this, null, options, false);
		}
	},

	load: null,
	
	//这里是一个模板方法，由子类来实现
	//this.proxy.request('read',null,{username:'abc',age:11},this.reader,fn,this,{params:{sort:'age',dir:'desc'},baseParams:{xxxx},params:{XXXXXXXXX}}});
	doRequest: function( action, rs, params, reader, callback, scope, options )
	{
		//this.load({username:'abc',age:11},reader,callback,scope,{params:{sort:'age',dir:'desc'},baseParams:{xxxx},params:{XXXXXXXXX}}});
		this.load(params, reader, callback, scope, options);
	},

	onRead: Ext.emptyFn,
	onWrite: Ext.emptyFn,
	buildUrl: function( action, record )
	{
		record = record || null;

		// conn.url gets nullified after each request. If it's NOT null here, that means the user must have intervened with a call
		// to DataProxy#setUrl or DataProxy#setApi and changed it before the request was executed. If that's the case, use conn.url,
		// otherwise, build the url from the api or this.url.
		var url = (this.conn && this.conn.url) ? this.conn.url : (this.api[action]) ? this.api[action].url : this.url;
		if( !url )
		{
			throw new Ext.data.Api.Error('invalid-url', action);
		}

		// look for urls having "provides" suffix used in some MVC frameworks like Rails/Merb and others. The provides suffice informs
		// the server what data-format the client is dealing with and returns data in the same format (eg: application/json, application/xml, etc)
		// e.g.: /users.json, /users.xml, etc.
		// with restful routes, we need urls like:
		// PUT /users/1.json
		// DELETE /users/1.json
		var provides = null;
		var m = url.match(/(.*)(\.json|\.xml|\.html)$/);
		if( m )
		{
			provides = m[2]; // eg ".json"
			url = m[1]; // eg: "/users"
		}
		// prettyUrls is deprectated in favor of restful-config
		if( (this.restful === true || this.prettyUrls === true) && record instanceof Ext.data.Record && !record.phantom )
		{
			url += '/' + record.id;
		}
		return (provides === null) ? url : url + provides;
	},

	/**
	 * Destroys the proxy by purging any event listeners and cancelling any active requests.
	 */
	destroy: function()
	{
		this.purgeListeners();
	}
});

// Apply the Observable prototype to the DataProxy class so that proxy instances can relay their
// events to the class. Allows for centralized listening of all proxy instances upon the DataProxy class.
Ext.apply(Ext.data.DataProxy, Ext.util.Observable.prototype);
Ext.util.Observable.call(Ext.data.DataProxy);

Ext.data.DataProxy.Error = Ext.extend(Ext.Error,
{
	constructor: function( message, arg )
	{
		this.arg = arg;
		Ext.Error.call(this, message);
	},
	name: 'Ext.data.DataProxy'
});
Ext.apply(Ext.data.DataProxy.Error.prototype,
{
	lang:
	{
		'action-undefined': "DataProxy attempted to execute an API-action but found an undefined url / function.  Please review your Proxy url/api-configuration.",
		'api-invalid': 'Recieved an invalid API-configuration.  Please ensure your proxy API-configuration contains only the actions from Ext.data.Api.actions.'
	}
});
